package com.zzj.controller;

import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson2.JSON;
import com.zzj.annotation.LogAnnotation;
import com.zzj.base.Result;
import com.zzj.entity.File;
import com.zzj.model.dto.file.RenameDto;
import com.zzj.model.dto.file.SearchDto;
import com.zzj.service.IFileService;
import com.zzj.service.IFolderService;
import com.zzj.utils.FileUtil;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.annotation.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;

import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * <p>
 * 文件表 前端控制器
 * </p>
 *
 * @author zzj
 * @since 2023-11-14
 */
@RestController
@RequestMapping("/file")
public class FileController {

    @Resource
    private IFileService fileService;
    @Resource
    private IFolderService folderService;

    @Resource
    private FileUtil fileUtil;

    @Transactional
    @LogAnnotation(name = "上传文件", description = "上传文件")
    @Operation(summary = "上传文件", description = "上传文件", tags = {"File"})
    @PostMapping("/uploadFile")
    public Result<?> uploadFile(
            @RequestParam("file") MultipartFile file,
            @RequestParam("parentId") String parentId,
            @RequestParam("creatorId") String creatorId,
            @RequestParam("pathName") String pathName) throws IOException {
        if (file.isEmpty()) {
            return Result.error("上传失败，请选择文件");
        }
        pathName = pathName + "tmp";
        boolean b = folderService.checkParentValid(creatorId, pathName, parentId);
        if (!b) {
            return Result.error("路径错误");
        }
        String path = fileUtil.upload(file);
        String name = file.getOriginalFilename();
        b = fileService.checkExist(creatorId, name, parentId);
        if (b) {
            name = fileUtil.getFileName(file) + "-" + RandomUtil.randomString(5) + "." + fileUtil.getFileType(file);
        }
        File newFile = fileService.create(creatorId, name, fileUtil.getFileSize(file), path, parentId);
        if (newFile != null) {
            return Result.success("上传成功", newFile);
        }
        return Result.error();
    }

    @Transactional
    @LogAnnotation(name = "全局关键字搜索文件", description = "全局关键字搜索文件")
    @Operation(summary = "全局关键字搜索文件", description = "全局关键字搜索文件", tags = {"File"})
    @PostMapping("/search")
    public Result<?> search(@RequestBody @Validated SearchDto in) {
        List<File> files = fileService.queryList(in.getCreatorId(), in.getSearchKey(), true);
        return Result.success("查询成功", files);
    }

    @Transactional
    @LogAnnotation(name = "删除文件", description = "删除文件")
    @Operation(summary = "删除文件", description = "删除文件", tags = {"File"})
    @PostMapping("/remove")
    public Result<?> remove(@RequestParam("id") String id) {
        boolean b = fileService.remove(id);
        if (b) {
            return Result.success("删除成功");
        }
        return Result.error("删除失败");
    }

    @Transactional
    @LogAnnotation(name = "重命名文件", description = "重命名文件")
    @Operation(summary = "重命名文件", description = "重命名文件", tags = {"File"})
    @PostMapping("/rename")
    public Result<?> rename(@RequestBody @Validated RenameDto in) {
        boolean b = fileService.updateName(in.getId(), in.getParentId(), in.getNewName());
        if (b) {
            return Result.success("重命名成功");
        }
        return Result.error("重命名失败");
    }


    @Transactional
    @LogAnnotation(name = "下载文件", description = "下载文件")
    @Operation(summary = "下载文件", description = "下载文件", tags = {"File"})
    @GetMapping("/download")
    public ResponseEntity<StreamingResponseBody> download(@RequestParam("id") String id) {
        File one = fileService.getById(id);
        if (one == null) {
            return ResponseEntity.ok()
                    .headers(new HttpHeaders())
                    .body(responseBody -> responseBody.write(JSON.toJSONString(Result.error("数据库找不到该文件")).getBytes(StandardCharsets.UTF_8)));
        }
        java.io.File file = fileUtil.getFile(one.getPath());
        if (file == null) {
            return ResponseEntity.ok()
                    .headers(new HttpHeaders())
                    .body(responseBody -> responseBody.write(JSON.toJSONString(Result.error(one.getName() + "  文件资源不存在")).getBytes(StandardCharsets.UTF_8)));

        }
        // 设置响应头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        headers.setContentDispositionFormData("attachment", URLEncoder.encode(one.getName(), StandardCharsets.UTF_8));
        // 构造StreamingResponseBody
        StreamingResponseBody responseBody = outputStream -> {
            try (FileInputStream fileInputStream = new FileInputStream(file)) {
                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = fileInputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
            }
        };

        // 返回ResponseEntity，包含StreamingResponseBody和响应头
        return ResponseEntity.ok()
                .headers(headers)
                .body(responseBody);
    }
}
